import sys
import xlrd
import copy
from collections import OrderedDict
from lxml.html import etree as et

count = 0

class NodeInfo():
	def __init__(self, typ="", name="", writable="", enum_val=[], default_v="", func="", hidden=""):
		self.type = typ
		self.name = name
		self.writable = writable
		self.enum_val = enum_val
		self.default = default_v
		self.function = func
		self.hidden = hidden

	def to_xml_node(self):
		attr_table = OrderedDict()
		attr_table['type'] = self.type
		attr_table['name'] = self.name
		if self.type != "object":
			attr_table["value"] = self.default
			if self.hidden != "":
				attr_table["hidden"] = self.hidden
			if self.function != "":
				attr_table["function"] = self.function
			if len(self.enum_val) > 0:
				enum_str = ''
				enum_cnt = len(self.enum_val)
				for i in range(0, enum_cnt - 1):
					enum_str += (self.enum_val[i] + ',')
				attr_table["enumeration"] = enum_str + enum_str[enum_cnt - 1]
		attr_table["writable"] = self.writable
		if self.type != "object":
			return et.Element("PARAMETER", attr_table)
		else:
			return et.Element("OBJECT", attr_table)


def NodeInfo_TEST_FUNC():
	node_info = NodeInfo("unsignedInt", "Enable", "1", [0, 1], "0", "GetEnable", "0")
	xml_node = node_info.to_xml_node()
	assert isinstance(xml_node, et._Element)
	print(xml_node.items())


class MergeXML():
	def __init__(self):
		pass

	def add_object_node(self, path, root):
		object_name_list = path.split('.')
		for i in range(0, len(object_name_list) - 1):
			object_name = object_name_list[i]
			node_list = root.xpath('./OBJECT[@name=\"%s\"]' % (object_name + '.'))
			if len(node_list) == 0:
				new_node = NodeInfo("object", object_name + '.', "0").to_xml_node()
				root.append(new_node)
				root = new_node
			else:
				root = node_list[0]
		object_name = object_name_list[len(object_name_list) - 1]
		node_list = root.xpath("./PARAMETER[@name=\"%s\"]" % (object_name))
		if len(node_list) > 0:
			return None
		else:
			return root

	def get_node(self, path, root):
		object_name_list = path.split('.')
		for i in range(0, len(object_name_list) - 1):
			object_name = object_name_list[i]
			node_list = root.xpath("./OBJECT[@name=\"%s\"]" % (object_name + '.'))
			if len(node_list) > 0:
				root = node_list[0]
			else:
				new_node = NodeInfo('object', object_name + '.', '0').to_xml_node()
				root.append(new_node)
				root = new_node
		object_name = object_name_list[len(object_name_list)-1]
		node_list = root.xpath("./PARAMETER[@name=\"%s\"]" % (object_name))
		if len(node_list) == 0:
			return None
		else:
			return node_list[0]

	def merge(self, path_list, src_root, dst_root):
		global count
		for path in path_list:
			dst_node = self.add_object_node(path, dst_root)
			if dst_node is None:
				print('%s has been exist' % path)
				continue
			#print(path)
			src_node = self.get_node(path, src_root)
			if src_node is None:
				print(count, '======= %s' % path)
				count += 1
				continue
			#print(src_root.attrib)
			assert isinstance(src_node, et._Element)
			#leaf_node = copy.deepcopy(src_node)
			leaf_node = et.Element(src_node.tag, src_node.attrib)
			dst_node.append(leaf_node)

class ParseFromXLS():
	def __init__(self, fn):
		self.root = et.Element('DataModel')
		self.workbook = xlrd.open_workbook(fn)
		self.sheet = self.workbook.sheet_by_name('TR-181')
		self.cur_node = None

	def add_object_node(self, name):
		pass

	def parse_row(self, row):
		# get all data we need
		name_str = str(row[0].value)
		type_str = str(row[1].value)
		writable_str = str(row[2].value)
		enum_str = str(row[3].value)
		default_v_str = str(row[4].value)
		hidden_str = str(row[7].value)
		function_str = str(row[8].value)
		enum_list = []

		if name_str.endswith('.') is True and type_str == "object":
			# current row descript an OBJECT node
			# split the node path
			name_str = name_str.replace('{i}', '0')
			name_list = name_str.split('.')
			node = self.root
			#check if every node in the path is exist
			for i in range(0, len(name_list) - 1):
				sub_node_list = node.xpath(".//OBJECT[@name=\'%s\']" % (name_list[i] + '.'))
				#print(sub_node_list)
				if len(sub_node_list) == 0:
					# if this node is not exist, we add this node and it's child
					assert isinstance(node, et._Element)
					writable_str = "0"
					for j in range(i, len(name_list) - 1):
						sub_node = NodeInfo('object', name_list[j] + '.', writable_str).to_xml_node()
						node.append(sub_node)
						node = sub_node
					self.cur_node = node
					break
				else:
					self.cur_node = node = sub_node_list[0]
					#print('--', [name_str, type_str, writable_str, default_v_str, function_str, hidden_str, enum_list])
		else:
			# current node is a leaf node
			name_str = name_str.strip()
			type_str = type_str.replace('\xad', '').replace('-', '').strip()
			if writable_str.upper() == 'W':
				writable_str = '1'
			else:
				writable_str = '0'

			if enum_str.find('Enumeration') >= 0:
				enum_str.replace('\r', '')
				enum_list = enum_str.split('\n')[1:]
				if '' in enum_list:
					enum_list.remove('')

			if default_v_str == '\xad' or default_v_str == '-':
				default_v_str = ''
			else:
				if default_v_str == "<Empty>":
					default_v_str = ""
				else:
					default_v_str = default_v_str.strip('"')

			if hidden_str != '':
				assert isinstance(hidden_str, str)
				hidden_str = hidden_str.strip()[1:]

			if function_str != '':
				function_str = function_str.strip()

			self.cur_node.append(NodeInfo(type_str, name_str,
			                              writable_str, enum_list,
			                              default_v_str, function_str,
			                              hidden_str).to_xml_node())
	def parse(self):
		for i in range(2, self.sheet.nrows):
			if self.sheet.cell(i, 0).value == "":
				break
			self.parse_row(self.sheet.row(i))

		return self.root

def main():
	parse_xls = ParseFromXLS('data.xls')
	dst_root = parse_xls.parse()
	with open('default.xml', encoding='utf-8') as fin:
		xml_str = fin.read().encode('utf-8')
		src_root = et.fromstring(xml_str)
	with open('data') as fin:
		path_list = [ line.replace('\n', '').replace('%d', '0') for line in fin ]
	merge_xml = MergeXML()
	merge_xml.merge(path_list, src_root, dst_root)
	assert isinstance(dst_root, et._Element)
	xml_tree = et.ElementTree(dst_root)
	assert isinstance(xml_tree, et._ElementTree)
	with open('result.xml', mode='w', encoding='utf-8') as fout:
		fout.write(et.tostring(dst_root, encoding='utf-8', pretty_print=True).decode('utf-8'))

if __name__ == '__main__':
	main()


def get_xml_path_list(fn):
	parent_node = ''
	path_list = []
	book = xlrd.open_workbook(fn)
	sheet = book.sheet_by_name('TR-181')
	for i in range(2, sheet.nrows):
		val = sheet.cell(i, 0).value
		if val.endswith('.'):
			parent_node = val
			path_list.append(parent_node)
		elif len(sheet.cell_value(i, 0)) > 0:
			path_list.append(parent_node + val)
		else:
			break
	for path in path_list:
		print(path)
	return path_list